package cn.ges.movie.service.impl

import cn.ges.date.DateUtil
import cn.ges.movie.entity.*
import cn.ges.movie.mapper.*
import cn.ges.movie.service.MovieService
import cn.ges.page.PageHelper
import cn.ges.random.RandomUtil
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.ges.common.config.jwt.JwtUtil
import com.ges.common.config.jwt.UserSigningKeyResolver
import com.ges.common.dto.MsgDTO
import com.ges.common.service.auth.UserKeyInfoService
import com.ges.common.vo.JwtVO
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
import javax.annotation.Resource

/**
 *
 * @author gespent@163.com
 * @date 2021/4/16 16:40
 */
@Service
open class MovieServiceImpl : MovieService {
    private val log = LoggerFactory.getLogger(MovieService::class.java)

    @Resource
    lateinit var movieMapper: MovieMapper

    @Resource
    lateinit var thisService: MovieService

    @Resource
    lateinit var cinemaMapper: MvCinemaMapper

    @Resource
    lateinit var movieHallMapper: MvMovieHallMapper

    @Resource
    lateinit var schedulingMapper: MvSchedulingMapper

    @Resource
    lateinit var ticketMapper: MvTicketMapper

    @Resource
    lateinit var userKeyInfoService: UserKeyInfoService

    @Resource
    lateinit var userSigningKeyResolver: UserSigningKeyResolver

    override fun inspectTicket(auth:String): MsgDTO {
        try {
            val sign = JwtUtil.sign(auth, userSigningKeyResolver)
            // 影票ID
            val subject = sign!!.subject
            val selectById = ticketMapper.selectById(subject.toLong()) ?: return MsgDTO.fail("不存在的电影票")
            selectById.tState = 1
            return if (ticketMapper.updateById(selectById) > 0) {
                MsgDTO.success("验票成功")
            } else {
                MsgDTO.fail("请稍后再试")
            }
        } catch (e: Exception) {
            return MsgDTO.fail("影票有误")
        }
    }



    /**
     * 获得验票AUTH
     */
    override fun getQcode(tId:Long,userId: Long): MsgDTO {
        // 获得影票信息
        val selectById = ticketMapper.selectById(tId) ?: return MsgDTO.fail("不存在的电影票")
        if (selectById.userId != userId) {
            return MsgDTO.fail("这张电影票不属于你")
        }
        if (selectById.tState == 1) {
            return MsgDTO.fail("这张票已验票")
        }
        // 排期信息
        val geMscById = thisService.geMscById(selectById.mscId!!)!!
        // 门票ID=USER_ID
        // AUTH=TICKET
        val nowUntilSecond = DateUtil.nowUntilSecond(DateUtil.instantToLocalDateTime(geMscById.endTime!!))
        if (nowUntilSecond <= 0) {
            return MsgDTO.fail("该场电影已经放映结束")
        }
        val byId = userKeyInfoService.getById(tId)
        return if (byId != null) {
            val creatJwt = JwtUtil.creatJwt(nowUntilSecond, "TICKET", byId.id!!, byId.jwtPri, "TICKET")
            return MsgDTO.successAndData(JwtVO().apply {
                jwt = creatJwt
            })

        } else {
            userKeyInfoService.userLoginAndRefreshUserKeyInfoWithEx(tId, nowUntilSecond, "TICKET", "TICKET")
        }
    }

    /**
     * 查询用户电影票信息
     */
    override fun listUserTicket(userId: Long, size: Int, current: Int): Pair<Int, MutableList<MvTicket>> {
        val apply = QueryWrapper<MvTicket>().apply {
            eq("user_id", userId)
        }
        // 查询票数
        val selectCount = ticketMapper.selectCount(apply)
        if (selectCount > 0) {
            apply.last(PageHelper.getActualLimitString(size, current))
            // 查询具体详情
            return selectCount to ticketMapper.selectList(apply)
        }
        return selectCount to ArrayList()
    }

    override fun listAllMovie(): MutableList<Movie> {
        return movieMapper.selectList(null)
    }

    /**
     * 获得所有电影院
     */
    override fun getAllCinema(): MutableList<MvCinema> {
        return cinemaMapper.selectList(null)
    }

    /**
     * 获得电影院信息
     */
    override fun getCmById(id:Long): MvCinema? {
        return cinemaMapper.selectById(id)
    }


    /**
     * 获得电影
     */
    override fun geMvById(id:Long): Movie? {
        return movieMapper.selectById(id)
    }

    /**
     * 获得放映厅信息
     */
    override fun geMvhById(id:Long): MvMovieHall? {
        return movieHallMapper.selectById(id)
    }

    /**
     * 获得排期
     */
    override fun geMscById(id:Long): MvScheduling? {
        return schedulingMapper.selectById(id)
    }



    /**
     * 初始化所有放映厅 每个电影院 三个放映厅 分别为ABC
     */
    @Transactional
    override fun initMVH() {
        val allCinema = getAllCinema()
        for (mvCinema in allCinema) {
            MvMovieHall().apply {
                id = RandomUtil.getSequence()
                mcId = mvCinema.id
                name = mvCinema.name + "A放映厅"
                maxCount = RandomUtil.getNumberRandomValue(100, 300)!!.toInt()
            }.run {
                movieHallMapper.insert(this)
            }
            MvMovieHall().apply {
                id = RandomUtil.getSequence()
                mcId = mvCinema.id
                name = mvCinema.name + "B放映厅"
                maxCount = RandomUtil.getNumberRandomValue(100, 300)!!.toInt()
            }.run {
                movieHallMapper.insert(this)
            }
            MvMovieHall().apply {
                id = RandomUtil.getSequence()
                mcId = mvCinema.id
                name = mvCinema.name + "C放映厅"
                maxCount = RandomUtil.getNumberRandomValue(100, 300)!!.toInt()
            }.run {
                movieHallMapper.insert(this)
            }
            log.info("初始化${mvCinema.name}的放映厅成功")
        }
    }

    /**
     * 按照日期为该日的所有放映厅排班 A=1 B=2 C=3 并设置到晚上7点开始
     */
    override fun initMvByDate(time: LocalDate) {
        val atTime = time.atTime(19, 0)
        val localDateTime2Instant = DateUtil.localDateTime2Instant(atTime)
        val selectList = movieHallMapper.selectList(null)
        log.info("总计有${selectList.size}条放映厅记录 开始初始化")
        selectList.forEach {
            log.info("开始初始化${it.name}")
            if (it.name!!.contains("A")) {
                val apply = MvScheduling().apply {
                    id = RandomUtil.getSequence()
                    this.mhId = it.id
                    startTime = localDateTime2Instant
                    endTime = localDateTime2Instant!!.plusSeconds(128 * 60)
                    mvId = 1
                    price = RandomUtil.getNumberRandomValue(50, 100)!!.toBigDecimal()
                }
                schedulingMapper.insert(apply)
                return@forEach
            }
            if (it.name!!.contains("B")) {
                val apply = MvScheduling().apply {
                    id = RandomUtil.getSequence()
                    this.mhId = it.id
                    startTime = localDateTime2Instant
                    endTime = localDateTime2Instant!!.plusSeconds(127 * 60)
                    mvId = 2
                    price = RandomUtil.getNumberRandomValue(50, 100)!!.toBigDecimal()
                }
                schedulingMapper.insert(apply)
                return@forEach
            }
            if (it.name!!.contains("C")) {
                val apply = MvScheduling().apply {
                    id = RandomUtil.getSequence()
                    this.mhId = it.id
                    startTime = localDateTime2Instant
                    endTime = localDateTime2Instant!!.plusSeconds(112 * 60)
                    mvId = 3
                    price = RandomUtil.getNumberRandomValue(50, 100)!!.toBigDecimal()
                }
                schedulingMapper.insert(apply)
                return@forEach
            }
        }
    }

}
